package com.zaker.touchtv.component;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.util.Log;
import android.util.Property;

public class PlayPauseDrawable extends Drawable {

  final static String LOG_TAG = "PlayPauseDrawable";

  private final static int DEFAULT_PAUSE_BAR_WIDTH = 10;

  private final static int DEFAULT_PAUSE_BAR_DISTANCE = 6;

  private final static int DEFAULT_PAUSE_BAR_HEIGHT = 28;

  private static final Property<PlayPauseDrawable, Float> PROGRESS =
      new Property<PlayPauseDrawable, Float>(Float.class, "progress") {
        @Override
        public Float get(PlayPauseDrawable d) {
          return d.getProgress();
        }

        @Override
        public void set(PlayPauseDrawable d, Float value) {
          d.setProgress(value);
        }
      };

  private final Path mLeftPauseBar = new Path();
  private final Path mRightPauseBar = new Path();
  private final Paint mPaint = new Paint();
  private final RectF mBounds = new RectF();
  private final float mPauseBarWidth;
  private final float mPauseBarHeight;
  private final float mPauseBarDistance;

  private float mWidth;
  private float mHeight;

  private float mProgress = 1f;
  private boolean mIsPlay = true;

  public PlayPauseDrawable(Context context) {

    mPaint.setAntiAlias(true);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setColor(Color.WHITE);

    float scale = context.getResources().getDisplayMetrics().density;
    mPauseBarWidth = evenNumber((int) (DEFAULT_PAUSE_BAR_WIDTH * scale + 0.5f));
    mPauseBarHeight = evenNumber((int) (DEFAULT_PAUSE_BAR_HEIGHT * scale + 0.5f));
    mPauseBarDistance = evenNumber((int) (DEFAULT_PAUSE_BAR_DISTANCE * scale + 0.5f));
  }

  @Override
  protected void onBoundsChange(Rect bounds) {
    super.onBoundsChange(bounds);
    mBounds.set(bounds);
    mWidth = mBounds.width();
    mHeight = mBounds.height();
  }

  @Override
  public void draw(@NonNull Canvas canvas) {
    mLeftPauseBar.rewind();
    mRightPauseBar.rewind();

    // The current distance between the two pause bars.
    final float barDist = lerp(mPauseBarDistance, 0, mProgress);
    // The current width of each pause bar.
    final float barWidth = lerp(mPauseBarWidth, mPauseBarHeight / 2f, mProgress);
    // The current position of the left pause bar's top left coordinate.
    final float firstBarTopLeft = lerp(0, barWidth, mProgress);
    // The current position of the right pause bar's top right coordinate.
    final float secondBarTopRight = lerp(2 * barWidth + barDist, barWidth + barDist, mProgress);

    Log.i(LOG_TAG, "\n draw mProgress: " + mProgress
        + " mPauseBarWidth: " + mPauseBarWidth + " mPauseBarHeight: " + mPauseBarHeight
        + " mWidth: " + mWidth + " mHeight: " + mHeight);
    Log.i(LOG_TAG, " draw barDist: " + barDist + " barWidth: " + barWidth
        + " firstBarTopLeft: " + firstBarTopLeft + " secondBarTopRight: " + secondBarTopRight
        + " \n");

    // Draw the left pause bar. The left pause bar transforms into the
    // top half of the play button triangle by animating the position of the
    // rectangle's top left coordinate and expanding its bottom width.
    mLeftPauseBar.moveTo(0, 0);
    mLeftPauseBar.lineTo(firstBarTopLeft, -mPauseBarHeight);
    mLeftPauseBar.lineTo(barWidth, -mPauseBarHeight);
    mLeftPauseBar.lineTo(barWidth, 0);
    mLeftPauseBar.close();

    // Draw the right pause bar. The right pause bar transforms into the
    // bottom half of the play button triangle by animating the position of the
    // rectangle's top right coordinate and expanding its bottom width.
    mRightPauseBar.moveTo(barWidth + barDist, 0);
    mRightPauseBar.lineTo(barWidth + barDist, -mPauseBarHeight);
    mRightPauseBar.lineTo(secondBarTopRight, -mPauseBarHeight);
    mRightPauseBar.lineTo(2 * barWidth + barDist, 0);
    mRightPauseBar.close();

    canvas.save();

    // Translate the play button a tiny bit to the right so it looks more centered.
    final float translateX = lerp(0, mPauseBarHeight / 8f, mProgress);
    canvas.translate(translateX, 0);

    // (1) Pause --> Play: rotate 0 to 90 degrees clockwise.
    // (2) Play --> Pause: rotate 90 to 180 degrees clockwise.
    final float rotationProgress = mIsPlay ? 1 - mProgress : mProgress;
    final float startingRotation = mIsPlay ? 90 : 0;

    canvas.rotate(lerp(startingRotation, startingRotation + 90, rotationProgress), mWidth / 2f, mHeight / 2f);

    // Position the pause/play button in the center of the drawable's bounds.
    canvas.translate(mWidth / 2f - ((2 * barWidth + barDist) / 2f), mHeight / 2f + (mPauseBarHeight / 2f));

    // Draw the two bars that form the animated pause/play button.
    canvas.drawPath(mLeftPauseBar, mPaint);
    canvas.drawPath(mRightPauseBar, mPaint);

    canvas.restore();
  }

  public Animator getPausePlayAnimator() {
    final Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, mIsPlay ? 1 : 0, mIsPlay ? 0 : 1);
    anim.addListener(new AnimatorListenerAdapter() {
      @Override
      public void onAnimationEnd(Animator animation) {
        mIsPlay = !mIsPlay;
      }
    });
    return anim;
  }

  public boolean isPlay() {
    return mIsPlay;
  }

  private void setProgress(float progress) {
    mProgress = progress;
    invalidateSelf();
  }

  private float getProgress() {
    return mProgress;
  }

  private int evenNumber(int number) {
    if (number % 2 == 0) {
      return number;
    }
    return (number + 1);
  }

  public void setInitState(boolean isPlay) {
    if (isPlay) {
      mIsPlay = true;
      mProgress = 1f;
    } else {
      mIsPlay = false;
      mProgress = 0;
    }
  }

  @Override
  public void setAlpha(int alpha) {
    mPaint.setAlpha(alpha);
    invalidateSelf();
  }

  @Override
  public void setColorFilter(ColorFilter cf) {
    mPaint.setColorFilter(cf);
    invalidateSelf();
  }

  @Override
  public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
  }

  /**
   * Linear interpolate between a and b with parameter t.
   */
  private static float lerp(float a, float b, float t) {
    return a + (b - a) * t;
  }
}
